package com.yxc.cademo;

import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.util.encoders.Base64;

import javax.security.auth.x500.X500Principal;
import java.io.*;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Arrays;
import java.util.Date;
import java.util.Random;
import java.util.Set;

public class GMCA {
    // CN commonName 一般名字
    // L localityName 地方名
    // ST stateOrProvinceName 州省名
    // O organizationName 组织名
    // OU organizationalUnitName 组织单位名
    // C countryName 国家
    // STREET streetAddress 街道地址
    // DC domainComponent 领域
    // UID user id 用户ID
    public static final X500Principal ISS = new X500Principal("CN=IIE_ROOT,OU=IIE,C=CN,S=BJ,O=IIE,L=BJ");
    public static final String ROOT_CRT_FILE_NAME = "iie_root.crt";
    public static final String ROOT_CRT_PRIVATE_KEY_FILE_NAME = "iie_root_private.pem";
    public static final X500Principal SUBJECT = new X500Principal("CN=ADMIN,OU=CERT,C=CN,S=BJ,L=BJ");
    public static final String ADMIN_CRT_FILE_NAME = "admin.crt";
    public static final String ADMIN_CRT_PRIVATE_KEY_FILE_NAME = "admin.pem";
    public static final String SIGN_DATA = "1234567890098765";
    // 别名
    public static final String ALIAS = "IIE";
    public static final String PFX_PASSWORD = "123456";
    public static final String ADMIN_PFX_FILE_NAME = "admin.pfx";

    static {
        Security.addProvider(new BouncyCastleProvider());
        BouncyCastleProvider bc = new BouncyCastleProvider();
        Set<Provider.Service> services = bc.getServices();
        for (Provider.Service s : services) {
            if (s.toString().toUpperCase().contains("CIPHER")) {
                System.out.println(s.toString());
            }
        }
    }

    public static void main(String[] args) throws Exception {
//        genGMCACert();
//        genCertWithCaSign();
//        testDigitalSign();
//        testSM2EcDc();
//        testSaveGMKeyStore();
//        String sign = signData("1234567890098765", readFile("C:\\project\\iiecas\\finger-print-key-sdk\\finger-print-key-sdk\\admin.pem"));
//        System.out.println(sign);
        boolean b = verifySign("1234567890098765", "MEQCIDXKB+MbyxUqfSap56IFQGJ+0waplqPVvzCePie7dc8EAiBioLz6Li1oxxI0crjMTiZJ7Ib15wjIAO5GYERABDyddQ==", readFile("C:\\Users\\Administrator\\Desktop\\20241029指纹key最终初始化\\admin\\admin.crt"));
        System.out.println(b);
    }

    private static void genGMCACert() throws Exception {
        System.out.println("=============测试生成国密CA根证书=============");
        KeyPairGenerator g = KeyPairGenerator.getInstance("EC", "BC");

        g.initialize(new ECNamedCurveGenParameterSpec("sm2p256v1"));

        KeyPair p = g.generateKeyPair();

        PrivateKey privKey = p.getPrivate();
        PublicKey pubKey = p.getPublic();

        System.out.println("CA PrivateKey:" + Base64.toBase64String(privKey.getEncoded()));

        ContentSigner sigGen = new JcaContentSignerBuilder("SM3withSM2").setProvider("BC").build(privKey);
        // 序列号
        BigInteger serialNumber = BigInteger.valueOf(new Random().nextInt() & 0x7fffffff);
        // 有效期   10年
        long validity = 10 * 365 * 24L * 60L * 60L;
        Date firstDate = new Date();
        Date lastDate;
        lastDate = new Date();
        lastDate.setTime(firstDate.getTime() + validity * 1000);
        X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(ISS, serialNumber, firstDate, lastDate, ISS, pubKey);
//                .addExtension(new ASN1ObjectIdentifier("2.5.29.15"), true, new X509KeyUsage(0xfe))
//                .addExtension(new ASN1ObjectIdentifier("2.5.29.37"), true, new DERSequence(KeyPurposeId.anyExtendedKeyUsage))
//                .addExtension(new ASN1ObjectIdentifier("2.5.29.17"), true, new GeneralNames(new GeneralName[]
//                                {
//                                        new GeneralName(GeneralName.rfc822Name, "gmca@test.cn"),
//                                        new GeneralName(GeneralName.dNSName, "ca.test.cn")
//                                }));
        // 生成证书
        X509Certificate cert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certGen.build(sigGen));
        // 验证是否在有效期内
        cert.checkValidity(new Date());
        // 验证此证书是否使用与指定公钥对应的私钥进行签名。
        cert.verify(pubKey);
        // 输出证书
        ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
        CertificateFactory fact = CertificateFactory.getInstance("X.509", "BC");
        cert = (X509Certificate) fact.generateCertificate(bIn);
        // base64输出
        System.out.println("CA Cert:" + Base64.toBase64String(cert.getEncoded()));
        // 文件输出
        saveFile(ROOT_CRT_PRIVATE_KEY_FILE_NAME, privKey.getEncoded());
        saveFile(ROOT_CRT_FILE_NAME, cert.getEncoded());
        System.out.println("=============测试生成国密CA根证书=============");
    }


    private static void genCertWithCaSign() throws Exception {
        System.out.println("=============测试国密CA根证书签发国密证书=============");
        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        // 读取私钥
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(readFile(ROOT_CRT_PRIVATE_KEY_FILE_NAME));
        PrivateKey caPrivateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        // 读取证书
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X509", "BC");
        Certificate caRootCert = certificateFactory.generateCertificate(new FileInputStream(ROOT_CRT_FILE_NAME));

        KeyPairGenerator g = KeyPairGenerator.getInstance("EC", "BC");
        g.initialize(new ECNamedCurveGenParameterSpec("sm2p256v1"));
        // 生成密钥对
        KeyPair p = g.generateKeyPair();
        PrivateKey privKey = p.getPrivate();
        PublicKey pubKey = p.getPublic();

        // 序列号
        BigInteger serialNumber = BigInteger.valueOf(new Random().nextInt() & 0x7fffffff);
        // 有效期   10年
        long validity = 10 * 365 * 24L * 60L * 60L;
        Date firstDate = new Date();
        Date lastDate;
        lastDate = new Date();
        lastDate.setTime(firstDate.getTime() + validity * 1000);

        ContentSigner sigGen = new JcaContentSignerBuilder("SM3withSM2").setProvider("BC").build(caPrivateKey);
        X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(
                (X509Certificate) caRootCert,
                serialNumber,
                firstDate,
                lastDate,
                SUBJECT,
                pubKey
        );
//                .addExtension(new ASN1ObjectIdentifier("2.5.29.15"), true, new X509KeyUsage(X509KeyUsage.digitalSignature | X509KeyUsage.nonRepudiation))
//                .addExtension(new ASN1ObjectIdentifier("2.5.29.37"), true, new DERSequence(KeyPurposeId.anyExtendedKeyUsage))
//                .addExtension(new ASN1ObjectIdentifier("2.5.29.17"), true, new GeneralNames(new GeneralName[]
//                                {
//                                        new GeneralName(GeneralName.rfc822Name, "gmca@test.cn"),
//                                        new GeneralName(GeneralName.dNSName, "ca.test.cn")
//                                }));

        // 生成证书
        X509Certificate cert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certGen.build(sigGen));
        // 验证有效性
        cert.checkValidity(new Date());
        // 验证此证书是否使用与指定公钥对应的私钥进行签名
        cert.verify(caRootCert.getPublicKey());
        // 输出证书
        ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
        CertificateFactory fact = CertificateFactory.getInstance("X.509", "BC");
        cert = (X509Certificate) fact.generateCertificate(bIn);
        // base64输出
        System.out.println("custCert:" + Base64.toBase64String(cert.getEncoded()));
        System.out.println("custPrivateKey:" + Base64.toBase64String(privKey.getEncoded()));
        // 文件输出
        saveFile(ADMIN_CRT_FILE_NAME, cert.getEncoded());
        saveFile(ADMIN_CRT_PRIVATE_KEY_FILE_NAME, privKey.getEncoded());
        System.out.println("=============测试国密CA根证书签发国密证书=============");

    }

    private static void testDigitalSign() throws Exception {
        System.out.println("=============测试国密证书数字签名=============");
        // 读取私钥
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(readFile(ADMIN_CRT_PRIVATE_KEY_FILE_NAME));
        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        // 读取证书
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X509", "BC");
        Certificate certificate = certificateFactory.generateCertificate(new FileInputStream(ADMIN_CRT_FILE_NAME));
        Signature signature = Signature.getInstance("SM3withSM2", "BC");
        signature.initSign(privateKey);

        String signText = SIGN_DATA;
        signature.update(signText.getBytes("UTF-8"));
        // 签名
        byte[] digitalsignature = signature.sign();

        System.out.println("signText:" + signText);
        System.out.println("digitalsignature:" + Base64.toBase64String(digitalsignature));

        // 验证签名
        Signature signature1 = Signature.getInstance("SM3withSM2", "BC");
        signature1.initVerify(certificate.getPublicKey());
        signature1.update(signText.getBytes("UTF-8"));
        boolean result = signature1.verify(digitalsignature);
        System.out.println("verifyResult:" + result);
        // 验证签名，伪造数据
        Signature signature2 = Signature.getInstance("SM3withSM2", "BC");
        signature2.initVerify(certificate.getPublicKey());
        signature2.update((signText + "exception").getBytes("UTF-8"));
        boolean exceptionResult = signature2.verify(digitalsignature);
        System.out.println("exceptionVerifyResult:" + exceptionResult);

        System.out.println("=============测试国密证书数字签名=============");
    }


    private static void testSM2EcDc() throws Exception {

        System.out.println("=============测试国密SM2加解密=============");

        //从证书获取公钥
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X509", "BC");
        Certificate certificate = certificateFactory.generateCertificate(new FileInputStream(ADMIN_CRT_FILE_NAME));
        PublicKey publicKey = certificate.getPublicKey();
        //获取加密参数
        BCECPublicKey localECPublicKey = (BCECPublicKey) publicKey;
        ECParameterSpec localECParameterSpec = localECPublicKey.getParameters();
        ECDomainParameters localECDomainParameters = new ECDomainParameters(
                localECParameterSpec.getCurve(), localECParameterSpec.getG(),
                localECParameterSpec.getN());
        ECPublicKeyParameters localECPublicKeyParameters = new ECPublicKeyParameters(localECPublicKey.getQ(),
                localECDomainParameters);
        //待加密数据
        byte[] ebs = "123sssss测试".getBytes("UTF-8");

        System.out.println("原文:" + new String(ebs));
        //初始化加密引擎
        SM2Engine sm2EncEngine = new SM2Engine();
        sm2EncEngine.init(true, new ParametersWithRandom(localECPublicKeyParameters));
        //加密
        byte[] bs = sm2EncEngine.processBlock(ebs, 0, ebs.length);
        String es = Base64.toBase64String(bs);
        System.out.println("密文:" + es);

        //获取私钥
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(readFile(ADMIN_CRT_PRIVATE_KEY_FILE_NAME));
        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        //获取解密参数
        BCECPrivateKey sm2PriK = (BCECPrivateKey) privateKey;
        ECParameterSpec ecParameterSpec = sm2PriK.getParameters();
        ECDomainParameters ecDomainParameters = new ECDomainParameters(
                ecParameterSpec.getCurve(), ecParameterSpec.getG(),
                ecParameterSpec.getN());
        ECPrivateKeyParameters localECPrivateKeyParameters = new ECPrivateKeyParameters(
                sm2PriK.getD(), ecDomainParameters);
        //初始化解密引擎
        SM2Engine sm2DcEngine = new SM2Engine();
        sm2EncEngine.init(true, new ParametersWithRandom(localECPublicKeyParameters));
        sm2DcEngine.init(false, localECPrivateKeyParameters);
        bs = Base64.decode(es.getBytes("Utf-8"));
        byte[] b = sm2DcEngine.processBlock(bs, 0, bs.length);
        System.out.println("明文:" + new String(b));

        System.out.println("=============测试国密SM2加解密=============");
    }

    private static void testSaveGMKeyStore() throws Exception {
        System.out.println("=============测试国密证书PKCS12 KeyStore存取=============");
        // 读取私钥
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(readFile(ADMIN_CRT_PRIVATE_KEY_FILE_NAME));
        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        // 读取证书
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X509", "BC");
        Certificate certificate = certificateFactory.generateCertificate(new FileInputStream(ADMIN_CRT_FILE_NAME));
        // 生成pfx
        KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
        keyStore.load(null, null);
        keyStore.setKeyEntry(ALIAS, privateKey, PFX_PASSWORD.toCharArray(), new Certificate[]{certificate});
        // 写入文件
        keyStore.store(new FileOutputStream(ADMIN_PFX_FILE_NAME), PFX_PASSWORD.toCharArray());
        // 读取pfx
        KeyStore keyStore1 = KeyStore.getInstance("PKCS12", "BC");
        keyStore1.load(new FileInputStream(ADMIN_PFX_FILE_NAME), PFX_PASSWORD.toCharArray());
        // 获取证书
        Certificate certificate1 = keyStore1.getCertificate(ALIAS);
        // 获取私钥
        PrivateKey privateKey1 = (PrivateKey) keyStore1.getKey(ALIAS, PFX_PASSWORD.toCharArray());

        System.out.println("公钥证书存取前后对比:" + Arrays.equals(certificate1.getEncoded(), certificate.getEncoded()));
        System.out.println("私钥存取前后对比:" + Arrays.equals(privateKey.getEncoded(), privateKey1.getEncoded()));
        System.out.println("=============测试国密证书PKCS12 KeyStore存取=============");

    }


    public static void saveFile(String path, byte[] data) {
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(path);
            fileOutputStream.write(data);
            fileOutputStream.flush();
            fileOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    public static byte[] readFile(String path) throws Exception {
        FileInputStream fileInputStream = new FileInputStream(path);
        byte[] bytes = new byte[fileInputStream.available()];
        fileInputStream.read(bytes);
        return bytes;
    }


    private static byte[] getPriKeyByteFromP8(byte[] p8byte) throws Exception {

        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(p8byte);

        KeyFactory keyFactory = KeyFactory.getInstance("EC");

        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

        ASN1InputStream asn1InputStream = new ASN1InputStream(privateKey.getEncoded());

        ASN1Sequence p8 = (ASN1Sequence) asn1InputStream.readObject();

        ASN1InputStream asn1InputStream1 = new ASN1InputStream(((DEROctetString) p8.getObjectAt(2)).getOctets());

        ASN1Sequence gmPrivateKey = (ASN1Sequence) asn1InputStream1.readObject();

        byte[] gmPriKeyBytes = ((DEROctetString) gmPrivateKey.getObjectAt(1)).getOctets();

        return gmPriKeyBytes;
    }

    private static String getCertify(byte[] p12) throws CertificateException, NoSuchProviderException, KeyStoreException, IOException, NoSuchAlgorithmException {
        // 读取证书
//        CertificateFactory certificateFactory = CertificateFactory.getInstance("X509", "BC");
//        Certificate certificate = certificateFactory.generateCertificate(new ByteArrayInputStream(p12));
//        return Base64.toBase64String(certificate.getEncoded());
        // 读取pfx
        KeyStore keyStore1 = KeyStore.getInstance("PKCS12", "BC");
        keyStore1.load(new ByteArrayInputStream(p12), PFX_PASSWORD.toCharArray());
        // 获取证书
        Certificate certificate1 = keyStore1.getCertificate(ALIAS);
        return Base64.toBase64String(certificate1.getEncoded());
    }

    /**
     * 生成国密root ca证书
     * <p>
     * issuer字段含义
     * CN commonName 一般名字
     * L localityName 地方名
     * ST stateOrProvinceName 州省名
     * O organizationName 组织名
     * OU organizationalUnitName 组织单位名
     * C countryName 国家
     * STREET streetAddress 街道地址
     * DC domainComponent 领域
     * UID user id 用户ID
     *
     * @param serialNum:             证书序列号
     * @param validityYear:          有效期限，单位年
     * @param issuer:                签发人  new X500Principal("CN=IIE_ROOT,OU=IIE,C=CN,S=BJ,O=IIE,L=BJ")
     * @param alias:                 pfx文件别名
     * @param pfxPassword:           pfx文件保护密码
     * @param rootCrtFilePath:       输出crt证书路径
     * @param rootCrtBase64FilePath: 输出crt证书base64格式路径
     * @param rootPfxFilePath:       输出pfx文件路径
     * @param rootPublicKeyPath:     输出公钥路径
     * @param rootPrivateKeyPath:    输出私钥路径
     * @return byte[] 证书，二进制
     * @author YXC
     * @date 2024/10/29 11:05
     **/
    public static byte[] genRootCa(
            int serialNum,
            int validityYear,
            X500Principal issuer,
            String alias,
            String pfxPassword,
            String rootCrtFilePath,
            String rootCrtBase64FilePath,
            String rootPfxFilePath,
            String rootPublicKeyPath,
            String rootPublicKeyBase64FilePath,
            String rootPrivateKeyPath,
            String rootPrivateKeyBase64FilePath
    ) throws Exception {
        // 初始化秘钥服务
        KeyPairGenerator g = KeyPairGenerator.getInstance("EC", "BC");
        g.initialize(new ECNamedCurveGenParameterSpec("sm2p256v1"));
        // 生成密钥对
        KeyPair p = g.generateKeyPair();
        PrivateKey privKey = p.getPrivate();
        PublicKey pubKey = p.getPublic();

        ContentSigner sigGen = new JcaContentSignerBuilder("SM3withSM2").setProvider("BC").build(privKey);
        // 序列号
        BigInteger serialNumber = BigInteger.valueOf(serialNum);
        // 有效期
        long validity = validityYear * 365 * 24L * 60L * 60L;
        Date firstDate = new Date();
        Date lastDate;
        lastDate = new Date();
        lastDate.setTime(firstDate.getTime() + validity * 1000);
        X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(issuer, serialNumber, firstDate, lastDate, issuer, pubKey);
        // 生成证书
        X509Certificate cert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certGen.build(sigGen));
        // 生成pfx
        KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
        keyStore.load(null, null);
        keyStore.setKeyEntry(alias, privKey, pfxPassword.toCharArray(), new Certificate[]{cert});
        // 输出证书
        ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
        CertificateFactory fact = CertificateFactory.getInstance("X.509", "BC");
        cert = (X509Certificate) fact.generateCertificate(bIn);
        // base64输出证书
        saveFile(rootCrtBase64FilePath, Base64.toBase64String(cert.getEncoded()).getBytes(StandardCharsets.UTF_8));
        // 输出crt文件
        saveFile(rootCrtFilePath, cert.getEncoded());
        // 输出公钥
        saveFile(rootPublicKeyPath, pubKey.getEncoded());
        // base64输出公钥
        saveFile(rootPublicKeyBase64FilePath, Base64.toBase64String(pubKey.getEncoded()).getBytes(StandardCharsets.UTF_8));
        // 输出私钥
        saveFile(rootPrivateKeyPath, privKey.getEncoded());
        // base64输出私钥
        saveFile(rootPrivateKeyBase64FilePath, Base64.toBase64String(privKey.getEncoded()).getBytes(StandardCharsets.UTF_8));
        // 输出pfx文件
        keyStore.store(Files.newOutputStream(Paths.get(rootPfxFilePath)), pfxPassword.toCharArray());
        return cert.getEncoded();
    }

    /**
     * 使用根证书签发用户证书
     *
     * @param serialNum:                    设备序列号
     * @param validityYear:                 有效期，单位年
     * @param alias:                        pfx文件别名
     * @param pfxPassword:                  pfx文件保护密码
     * @param subject:                      用户信息，如：new X500Principal("CN=ADMIN,OU=CERT,C=CN,S=BJ,L=BJ");
     * @param rootPrivateKeyPath:           root证书私钥文件路径
     * @param rootCrtFilePath:              root证书文件路径
     * @param userCrtFilePath:              生成的用户证书文件路径
     * @param userCrtBase64FilePath:        生成的用户证书base64文件路径
     * @param userPfxFilePath:              生成的用户证书pfx文件路径
     * @param userPublicKeyPath:            生成的用户证书公钥文件路径
     * @param userPublicKeyBase64FilePath:  生成的用户证书公钥base64文件路径
     * @param userPrivateKeyPath:           生成的用户证书私钥文件路径
     * @param userPrivateKeyBase64FilePath: 生成的用户证书私钥base64文件路径
     * @return byte[]
     * @author YXC
     * @date 2024/10/29 11:22
     **/
    public static byte[] issueCertificate(
            int serialNum,
            int validityYear,
            String alias,
            String pfxPassword,
            X500Principal subject,
            String rootPrivateKeyPath,
            String rootCrtFilePath,
            String userCrtFilePath,
            String userCrtBase64FilePath,
            String userPfxFilePath,
            String userPublicKeyPath,
            String userPublicKeyBase64FilePath,
            String userPrivateKeyPath,
            String userPrivateKeyBase64FilePath
    ) throws Exception {
        // 初始化
        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        // 读取私钥
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(readFile(rootPrivateKeyPath));
        PrivateKey caPrivateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        // 读取证书
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X509", "BC");
        Certificate caRootCert = certificateFactory.generateCertificate(Files.newInputStream(Paths.get(rootCrtFilePath)));

        KeyPairGenerator g = KeyPairGenerator.getInstance("EC", "BC");
        g.initialize(new ECNamedCurveGenParameterSpec("sm2p256v1"));
        // 生成密钥对
        KeyPair p = g.generateKeyPair();
        PrivateKey privKey = p.getPrivate();
        PublicKey pubKey = p.getPublic();
        // 序列号
        BigInteger serialNumber = BigInteger.valueOf(serialNum);
        // 有效期
        long validity = validityYear * 365 * 24L * 60L * 60L;
        Date firstDate = new Date();
        Date lastDate;
        lastDate = new Date();
        lastDate.setTime(firstDate.getTime() + validity * 1000);

        ContentSigner sigGen = new JcaContentSignerBuilder("SM3withSM2").setProvider("BC").build(caPrivateKey);
        X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder((X509Certificate) caRootCert, serialNumber, firstDate, lastDate, subject, pubKey);

        // 生成证书
        X509Certificate cert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certGen.build(sigGen));
        // 生成pfx
        KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
        keyStore.load(null, null);
        keyStore.setKeyEntry(alias, privKey, pfxPassword.toCharArray(), new Certificate[]{cert});
        // 验证有效性
//        cert.checkValidity(new Date());
        // 验证此证书是否使用与指定公钥对应的私钥进行签名
//        cert.verify(caRootCert.getPublicKey());
        // 输出证书
        ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
        CertificateFactory fact = CertificateFactory.getInstance("X.509", "BC");
        cert = (X509Certificate) fact.generateCertificate(bIn);

        // base64输出证书
        saveFile(userCrtBase64FilePath, Base64.toBase64String(cert.getEncoded()).getBytes(StandardCharsets.UTF_8));
        // 输出crt文件
        saveFile(userCrtFilePath, cert.getEncoded());
        // 输出公钥
        saveFile(userPublicKeyPath, pubKey.getEncoded());
        // base64输出公钥
        saveFile(userPublicKeyBase64FilePath, Base64.toBase64String(pubKey.getEncoded()).getBytes(StandardCharsets.UTF_8));
        // 输出私钥
        saveFile(userPrivateKeyPath, privKey.getEncoded());
        // base64输出私钥
        saveFile(userPrivateKeyBase64FilePath, Base64.toBase64String(privKey.getEncoded()).getBytes(StandardCharsets.UTF_8));
        // 输出pfx文件
        keyStore.store(Files.newOutputStream(Paths.get(userPfxFilePath)), pfxPassword.toCharArray());
        return cert.getEncoded();
    }

    /**
     * 利用私钥和证书进行签名
     *
     * @param signData: 要签名的数据
     * @return java.lang.String
     * @author YXC
     * @date 2024/10/29 10:31
     * @Param privateKeyByte: 私钥，读取到的byte数据
     **/
    public static String signData(String signData, byte[] privateKeyByte) throws NoSuchAlgorithmException, InvalidKeySpecException, CertificateException, NoSuchProviderException, InvalidKeyException, UnsupportedEncodingException, SignatureException {
        // 获取私钥
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKeyByte);
        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        Signature signature = Signature.getInstance("SM3withSM2", "BC");
        signature.initSign(privateKey);
        // 开始签名
        signature.update(signData.getBytes("UTF-8"));
        // 签名
        byte[] digitalsignature = signature.sign();

        return Base64.toBase64String(digitalsignature);
    }

    /**
     * 使用证书验证签名
     *
     * @param signData: 签名之前的数据
     * @return boolean
     * @author YXC
     * @date 2024/10/29 10:39
     * @Param sign: 签名之后的数据
     * @Param certifyByte: 证书，读取到的byte数据
     **/
    public static boolean verifySign(String signData, String sign, byte[] certifyByte) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, UnsupportedEncodingException, CertificateException, SignatureException {
        // 获取证书
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X509", "BC");
        Certificate certificate = certificateFactory.generateCertificate(new ByteArrayInputStream(certifyByte));
        Signature signature = Signature.getInstance("SM3withSM2", "BC");
        // 获取公钥
        signature.initVerify(certificate.getPublicKey());
        signature.update(signData.getBytes("UTF-8"));
        boolean result = signature.verify(Base64.decode(sign));
        return result;
    }


}
